/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

****/
package org.activequant.data.retrieval.series;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.TimeZone;

import org.activequant.core.domainmodel.SeriesSpecification;
import org.activequant.core.domainmodel.data.Candle;
import org.activequant.core.domainmodel.data.CandleSeries;
import org.activequant.core.types.TimeFrame;
import org.activequant.core.types.TimeStamp;
import org.activequant.core.util.TimeSeriesUtils;
import org.activequant.core.util.TimeStampFormat;
import org.activequant.data.annotations.Vendor;
import org.activequant.data.retrieval.ICandleSeriesSource;
import org.apache.log4j.Logger;

/**
 * Access to Google Finance historical data.<br/>
 * GoogleCandleSeriesSource implements ICandleSeriesSource.<br/>
 * Holds the following associated variables:
 * <ul>
 * <li>outFormat(TimeStampFormat)</li>
 * <li>reqFormat(TimeStampFormat)</li>
 * </ul>
 * <b>History:</b><br>
 *  - [09.02.2008] Created (Mike Kroutikov)<br>
 *
 *  @author Mike Kroutikov
 */
@Vendor("Google")
public class GoogleCandleSeriesSource implements ICandleSeriesSource {

    private final static Logger log = Logger.getLogger(GoogleCandleSeriesSource.class);

    /**
     * private final static String URL_FORMAT = "http://finance.google.com/finance/historical?q={0}&output=csv&startdate={1}&enddate={2}&histperiod={3}";<br/>
     * i.e. http://finance.google.com/finance/historical?q=GOOG&output=csv&startdate=Feb+10,+2007&enddate=Aug+10,+2007
     */
    private final static String URL_FORMAT = "http://finance.google.com/finance/historical?q={0}&output=csv&startdate={1}&enddate={2}&histperiod={3}";
    /**
     * private final static TimeStampFormat outFormat = new TimeStampFormat("dd-MMM-yy", Locale.US);<br/>
     * Sets its TimeZone to "America/New_York" in  a static block
     */
    private final static TimeStampFormat outFormat = new TimeStampFormat("dd-MMM-yy", Locale.US);
    /**
     * private final static TimeStampFormat reqFormat = new TimeStampFormat("MMM+dd,+yyyy", Locale.US);<br/>
     * Sets its TimeZone to "America/New_York" in  a static block
     */
    private final static TimeStampFormat reqFormat = new TimeStampFormat("MMM+dd,+yyyy", Locale.US);
    static {
    	outFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    	reqFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    }

    public CandleSeries fetch(SeriesSpecification spec) throws Exception {

        log.info("Fetching candles.");

        if(spec.getStartTimeStamp () == null) {
        	throw new IllegalArgumentException("startTimeStamp is not set on the series specification: " + spec);
        }

        if(spec.getEndTimeStamp () == null) {
        	throw new IllegalArgumentException("endTimeStamp is not set on the series specification: " + spec);
        }

        String histperiod = "daily";
        if(spec.getTimeFrame().equals(TimeFrame.TIMEFRAME_1_DAY)) {
        } else if(spec.getTimeFrame().equals(TimeFrame.TIMEFRAME_1_WEEK)) {
        	histperiod = "weekly";
        } else {
        	throw new IllegalArgumentException("google supports only DAILY and WEEKLY candles: " + spec.getTimeFrame());
        }

        // parameters
        CandleSeries timeSeries = new CandleSeries(spec);
        
        String startDateRequest = reqFormat.format(spec.getStartTimeStamp());
        String endDateRequest = reqFormat.format(spec.getEndTimeStamp());
        
        String symbol = spec.getInstrumentSpecification().getSymbol().toString();
        if(spec.getInstrumentSpecification().getExchange() != null
        		&& spec.getInstrumentSpecification().getExchange().trim().length() > 0 ) {
        	symbol = spec.getInstrumentSpecification().getExchange().trim() + ":" + symbol;
        }
        
        // open url
        String urlStr = MessageFormat.format(
        		URL_FORMAT, symbol, startDateRequest, endDateRequest, histperiod);
        log.info("sending request [" + urlStr + "]");
        URL url = new URL(urlStr);
        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
        String line = reader.readLine();
        while ((line = reader.readLine()) != null) {
            log.info(line);
            String [] token = line.split(",");

            TimeStamp stamp = outFormat.parse(token[0].trim());
            double open = Double.parseDouble(token[1].trim());
            double high = Double.parseDouble(token[2].trim());
            double low = Double.parseDouble(token[3].trim());
            double close = Double.parseDouble(token[4].trim());
            double volume = token.length > 5 ? Double.parseDouble(token[5].trim()) : 0.0;
            
            Candle candle = new Candle(spec.getInstrumentSpecification());
            candle.setTimeStamp(stamp);
            candle.setOpenPrice(open);
            candle.setClosePrice(close);
            candle.setHighPrice(high);
            candle.setLowPrice(low);
            candle.setVolume(volume);
            candle.setTimeFrame(spec.getTimeFrame());

            if(stamp.compareTo(spec.getStartTimeStamp()) >= 0 && stamp.compareTo(spec.getEndTimeStamp()) <= 0) {
            	timeSeries.add(candle);
            }
        }

        log.info("Fetched " + timeSeries.size() + " candles.");

        TimeSeriesUtils.alignDateOrder(timeSeries);

        return timeSeries;
    }
}